#include "DigitalSignageManagerEx.h"
#include "Protocol/ProtocolApi.h"
#include "ScreenMirrorStream.h"
#include "DiskController.h"
#include "errorCode.h"
#include "Util/logc.h"

using namespace Protocol;

static std::string DigitalSignageConfigLocalPath = "/mnt/media/DigitalSignage/DigitalSignage.json";
static std::string DigitalSignageConfigSDPath = "/mnt/sd/DigitalSignage/DigitalSignage.json";

typedef enum{
    DigitalSignageItemType_Image,
    DigitalSignageItemType_Video,
}DigitalSignageItemType;


class DigitalSignageItemPlayInfo{
public:
    using Ptr = std::shared_ptr<DigitalSignageItemPlayInfo>;
    DigitalSignageItemPlayInfo(int fileSize, int fileDuration, int playDuration,
        const std::string& filePath, const std::string& cloudUrl):
        m_file_size(fileSize), m_file_duration(fileDuration), m_play_duration(playDuration),
        m_file_path(filePath), m_cloud_url(cloudUrl){

        }
    
    ~DigitalSignageItemPlayInfo(){

    }

    int FileSize(){
        return m_file_size;
    }
    int FileDuration(){
        return m_file_duration;
    }
    int PlayDuration(){
        return m_play_duration;
    }
    const std::string& FilePath(){
        return m_file_path;
    }
    const std::string& CloudUrl(){
        return m_cloud_url;
    }
private:
    int m_file_size;
    int m_file_duration;
    int m_play_duration;
    std::string m_file_path;
    std::string m_cloud_url;
};


class DigitalSignageItem{
public:
    using Ptr = std::shared_ptr<DigitalSignageItem>;
    DigitalSignageItem(const std::string& name, 
        DigitalSignageItemType itemType):
        m_item_id(0), m_play_index(0), m_name(name), 
        m_item_type(itemType), m_play_info(nullptr){

    }
    ~DigitalSignageItem(){

    }

    void SetPlayInfo(DigitalSignageItemPlayInfo::Ptr playinfo){
        m_play_info = playinfo;
    }

    void SetItemId(uint32_t id){
        m_item_id = id;
    }

    void SetPlayIndex(uint32_t index){
        m_play_index = index;
    }

    uint32_t ItemId(){
        return m_item_id;
    }

    uint32_t PlayIndex(){
        return m_play_index;
    }

    const std::string& Name(){
        return m_name;
    }

    DigitalSignageItemType ItemType(){
        return m_item_type;
    }

    DigitalSignageItemPlayInfo::Ptr PlayInfo(){
        return m_play_info;
    }

private:
    uint32_t m_item_id;
    uint32_t m_play_index;
    std::string m_name;
    DigitalSignageItemType m_item_type;
    DigitalSignageItemPlayInfo::Ptr m_play_info;
};


static bool parseDigitalSignageItem(const Json::Value& playList,
    std::vector<DigitalSignageItem::Ptr>& items, std::string& errorInfo){
    bool ret = false;
    if(playList.isArray()){
        int listSize = playList.size();
        for(int i = 0; i < listSize; i++){
            DigitalSignageItem::Ptr item;
            const Json::Value& itemInfo = playList[i];
            if(itemInfo.isObject()){
                std::string name = itemInfo["name"].asString();
                std::string type = itemInfo["type"].asString();
                DigitalSignageItemType d_type;
                if(type != "image" && type != "video" ){
                    errorInfo = "type not support";
                    return false;
                }
                if(type == "image"){
                    d_type = DigitalSignageItemType_Image;
                }else if(type == "video"){
                    d_type = DigitalSignageItemType_Video;
                }

                item = std::make_shared<DigitalSignageItem>(name, d_type);
                DigitalSignageItemPlayInfo::Ptr playinfo;
                if(itemInfo.isMember("fileSize") && itemInfo.isMember("fileDuration") && 
                    itemInfo.isMember("playDuration") && 
                    (itemInfo.isMember("filePath") || itemInfo.isMember("fileCloudUrl"))){
                        int fileSize = itemInfo["fileSize"].asInt();
                        int fileDuration = itemInfo["fileDuration"].asInt();
                        int playDuration = itemInfo["playDuration"].asInt();
                        std::string filePath = itemInfo["filePath"].asString();
                        std::string fileCloudUrl = itemInfo["fileCloudUrl"].asString();
                        playinfo = std::make_shared<DigitalSignageItemPlayInfo>(fileSize,
                            fileDuration, playDuration, filePath, fileCloudUrl);
                        item->SetPlayInfo(playinfo);
                }else{
                    errorInfo = "parse playList playInfo fail";
                    return false;
                }

                if(playinfo){
                    items.push_back(item);
                }
            }
        }
    }else{
        ret = false;
        errorInfo = "parse playList fail";
    }

    return ret;
}

static int getTotalDigitalSignageSize(const std::vector<DigitalSignageItem::Ptr>& items){
    int totalSize = 0;

    for(auto& item:items){
        totalSize += item->PlayInfo()->FileSize();
    }

    return totalSize;
}

static void restartFtp(){
    system("killall vsftpd  && nohup  vsftpd /user/cfg/vsftpd.conf & > /dev/null &");
}


DigitalSignageManagerEx::Ptr DigitalSignageManagerEx::Instance(){
    static DigitalSignageManagerEx::Ptr manager = std::make_shared<DigitalSignageManagerEx>();
    return manager;
}

DigitalSignageManagerEx::DigitalSignageManagerEx():m_digitalSignageState(DigitalSignageMachineState_Idle){
    // loadConfig();
    RegistRPC();
}

DigitalSignageManagerEx::~DigitalSignageManagerEx(){

}

void DigitalSignageManagerEx::RegistRPC(){

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("CreateDigitalSignage", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return createDigitalSignage(req_params, res_result, errinfo, errorCode);
        });
    
    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("AddDigitalSignage", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return addDigitalSignage(req_params, res_result, errinfo, errorCode);
        });

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("DelDigitalSignage", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return delDigitalSignage(req_params, res_result, errinfo, errorCode);
        });

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("GetDigitalSignage", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return getDigitalSignage(req_params, res_result, errinfo, errorCode);
        });

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("MoveDigitalSignage", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return moveDigitalSignage(req_params, res_result, errinfo, errorCode);
        });

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("PlayDigitalSignage", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return playDigitalSignage(req_params, res_result, errinfo, errorCode);
        });

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("StopDigitalSignage", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return stopDigitalSignage(req_params, res_result, errinfo, errorCode);
        });

    IProtocolInterface::GetInstance()->AuditoryworksRegistRequestRpcEx("SetDigitalSignage", 
        [this](const Json::Value& req_params, Json::Value& res_result, std::string& errinfo, int& errorCode){
            return setDigitalSignage(req_params, res_result, errinfo, errorCode);
        });
}
bool DigitalSignageManagerEx::Init(){

    return true;
}

void DigitalSignageManagerEx::loadConfig(const std::string& configFile){

}

bool DigitalSignageManagerEx::createDigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    //1.first determine whether the screen is being cast
    if(Media::ScreenMirrorStream::instance()->getShareScreenStatus())
    {
        errinfo = "The device is displaying screen mirroring information, please try again later.";
        errorCode = Media::ScreenPlaying;
        errorf("createDigitalSignage faild, errinfo=%s\n", errinfo.c_str());
		return false;        
    }
    

    //2.parse playList from req_params
    if(!req_params.isMember("playList")){
        errinfo = "not found playList";
        errorCode = Media::PlayListNotExist;
        errorf("createDigitalSignage faild, errinfo=%s\n", errinfo.c_str());
        return false;
    }

    std::vector<DigitalSignageItem::Ptr> items;
    if(!parseDigitalSignageItem(req_params["playList"], items, errinfo)){
        errorCode = Media::IllegalParameter;
        errorf("createDigitalSignage faild, errinfo=%s\n", errinfo.c_str());
        return false;
    }

    if(items.empty()){
        errorCode = Media::PlayListEmpty;
        errinfo = "playList is empty";
        errorf("createDigitalSignage faild, errinfo=%s\n", errinfo.c_str());
        return false;
    }

    //3.determine whether there is enough space in device

    // int fileTotalSize = getTotalDigitalSignageSize(items);
    // unsigned long long availableSpace = 0;
    // unsigned long long totalSpace = 0;
    
    // std::string path;
    // DiskController::instance()->getRealTimeRootPath(path);
    // DiskController::instance()->getDiskSpaceInfo(path, availableSpace, totalSpace);
    // unsigned long long dirSize = DiskController::instance()->calculateFolderSize(path + "/streamer");
    // if(availableSpace + dirSize < fileTotalSize){
    //     errorCode = Media::NoSpace;
    //     errinfo = "disk space not enough";
    //     errorf("createDigitalSignage faild, errinfo=%s\n", errinfo.c_str());
    //     return false;
    // }

    //4.reload config to digital signage configuration
    m_items.clear();
    m_items = items;
    for(int i = 0; i < m_items.size(); i++){
        m_items[i]->SetPlayIndex(i);
        m_items[i]->SetItemId(i);
    }

    m_digitalSignageId++;

    if(m_digitalSignageState == DigitalSignageMachineState_Prepare){
        //stop download task

        //restart ftp 
        restartFtp();
    }

    if(m_digitalSignageState == DigitalSignageMachineState_Playing){
        stopPlay();
    }

    handleNew();
    return true;
}

//In the current version, only the client send this request
bool DigitalSignageManagerEx::addDigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    //1.first determine whether the screen is being cast
    
    //2.parse digitalSignageId from req_params, if digitalSignageId not exist, return error

    //3.determine whether there is enough space in device

    //4.reload config to digital signage configuration

    return true;
}

//In the current version, only the client send this request
bool DigitalSignageManagerEx::delDigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    //1.first determine whether the screen is being cast

    //2.parse digitalSignageId from req_params, if digitalSignageId not exist, return error

    //3.reload config to digital signage configuration
    return true;
}

//In the current version, only the client send this request
bool DigitalSignageManagerEx::getDigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    //1.parse digitalSignageId from req_params, if digitalSignageId not exist, return error

    //2.return m_items to res_result
    return true;
}

//In the current version, only the client send this request
bool DigitalSignageManagerEx::moveDigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    //1.first determine whether the screen is being cast

    //2.parse digitalSignageId from req_params, if digitalSignageId not exist, return error

    //3.parse src itemId and dst itemId from req_params, if itemId not exist, return error

    //4.reload config to digital signage configuration

    //5.replay digital signage
    return true;
}

//In the current version, only the client send this request
bool DigitalSignageManagerEx::playDigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    //1.first determine whether the screen is being cast

    //2.parse digitalSignageId from req_params, if digitalSignageId not exist, return error

    //3.play digital signage
    return true;
}

//In the current version, only the client send this request
bool DigitalSignageManagerEx::stopDigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    //1.first determine whether the screen is being cast

    //2.parse digitalSignageId from req_params, if digitalSignageId not exist, return error

    //3.stop play digital signage
    return true;
}

//In the current version, only the client send this request
bool DigitalSignageManagerEx::setDigitalSignage(const Json::Value& req_params, Json::Value& res_result, 
        std::string& errinfo, int& errorCode){
    //1.first determine whether the screen is being cast

    //2.parse digitalSignageId from req_params, if digitalSignageId not exist, return error

    //3.parse playList from req_params

    //4.reload config to digital signage configuration

    //5.replay digital signage
    return true;
}


bool DigitalSignageManagerEx::waitFileComplete(){

    return true;
}

void DigitalSignageManagerEx::handleNew(){
    //1.Wait for the ftp all file transfer to complete  for client
    waitFileComplete();
    startPlay();
}

void DigitalSignageManagerEx::stopPlay(){

    m_digitalSignageState == DigitalSignageMachineState_Stop;
}

void DigitalSignageManagerEx::startPlay(){

    m_digitalSignageState == DigitalSignageMachineState_Playing;
}